//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <clsinfo.h>
#include <stub.h>
#include <syscall.h>
#include <kmarshal.h>
#include <kprxstub.h>
#include <svrobj.h>
#include "rot.h"

ECode CInterfaceStub::UnmarshalIn(
    /* [in] */ const CIMethodEntry *pMethodInfo,
    /* [in] */ MarshalHeader *pInHeader,
    /* [in] */ UInt32 * puOutInterfaceBuf,
    /* [in, out] */ UInt32 *puArgs)
{
    ECode ec = NOERROR;
    int n, cParams;
    CIBaseType *pParams;
    InterfacePack * pInterfacePack;

    assert(GET_INTERFACE_MARK(pMethodInfo->reserved1));
    cParams = pMethodInfo->paramNum;
    pParams = pMethodInfo->params;
    pInterfacePack = (InterfacePack *)((int *)(pInHeader + 1) + 1);

    for (n = 0; n < cParams; n++) {
        switch (BT_TYPE(pParams[n])) {
            case BT_TYPE_UINT8:
            case BT_TYPE_UINT16:
            case BT_TYPE_UINT32:
            case BT_TYPE_PUINT8:
            case BT_TYPE_PUINT16:
            case BT_TYPE_PUINT32:
            case BT_TYPE_PUINT64:
            case BT_TYPE_PEGUID:
            case BT_TYPE_PEMUID:
            case BT_TYPE_ASTRING:
            case BT_TYPE_WSTRING:
            case BT_TYPE_STRUCT:
            case BT_TYPE_PSTRUCT:
                puArgs++;
                break;

            case BT_TYPE_UINT64:
#ifdef _mips
                // Adjust for 64bits align on mips
                if (!(cParams % 2)) {
                    puArgs += 1;
                }
#endif
                puArgs += 2;
                break;

            case BT_TYPE_EGUID:
                puArgs += sizeof(EMuid) / 4 + sizeof(wchar_t *) / 4;
                break;

            case BT_TYPE_EMUID:
                puArgs += sizeof(EMuid) / 4;
                break;

            case BT_TYPE_INTERFACE:
                assert(BT_IS_IN(pParams[n]));

                if (*puArgs) {
                    ec = KernUnmarshalInterface(
                             pInterfacePack,
                             CTX_KERN_2_USER,
                             (IInterface **)puArgs);
                    if (FAILED(ec)) {
                        MARSHAL_DBGOUT(MSHDBG_ERROR, kprintf(
                            "MshUserToKern: marshal interface, ec = %x\n",
                                ec));
                        return ec;
                    }
                    pInterfacePack += 1;
                }
                puArgs++;
                break;

            case BT_TYPE_PINTERFACE:
                if (BT_IS_IN(pParams[n])) {
                    if (*puArgs && *(UInt32 *)(*puArgs)) {
                        UInt32 * pv = new UInt32;
                        if (!pv) return E_OUT_OF_MEMORY;
                        ec = KernUnmarshalInterface(
                                pInterfacePack,
                                CTX_KERN_2_USER,
                                (IInterface **)pv);
                        if (FAILED(ec)) {
                            delete pv;
                            MARSHAL_DBGOUT(MSHDBG_ERROR, kprintf(
                                "MshUserToKern: marshal interface, ec = %x\n",
                                    ec));
                            return ec;
                        }
                        *puArgs = (UInt32)pv;
                    }
                    pInterfacePack += 1;
                }
                else if (BT_IS_OUT(pParams[n])) {
                    if (*puArgs) {
                        *puOutInterfaceBuf = *(UInt32 *)*puArgs;
                        *puArgs = (UInt32)puOutInterfaceBuf;
                    }
                    else {
                        *puOutInterfaceBuf = NULL;
                    }

                    puOutInterfaceBuf++;
                }
                puArgs++;
                break;

                case BT_TYPE_WSTRINGBUF:
                case BT_TYPE_ASTRINGBUF:
                case BT_TYPE_BUFFEROF:
                case BT_TYPE_ARRAYOF:
                    if (*puArgs && CarQuintetFlag_Type_IObject
                        == (((PCARQUINTET)*puArgs)->m_flags
                                & CarQuintetFlag_TypeMask)
                        && BT_IS_IN(pParams[n])) {

                        *puArgs = (UInt32)(PCARQUINTET) \
                                        ((BufferOf<IInterface *>*)*puArgs)->Clone();

                        int used = ((PCARQUINTET)*puArgs)->m_used
                                    / sizeof(IInterface *);
                        int *pBuf = (int*)((PCARQUINTET)*puArgs)->m_pBuf;
                        for (int i = 0; i < used; i++) {
                            if (pBuf[i]) {
                                ec = KernUnmarshalInterface(
                                         pInterfacePack,
                                         CTX_KERN_2_USER,
                                         (IInterface **)&pBuf[i]);
                                if (FAILED(ec)) {
                                    MARSHAL_DBGOUT(MSHDBG_ERROR, kprintf(
                                        "MshUserToKern: marshal interface,"
                                        "ec = %x\n", ec));
                                    return ec;
                                }
                                pInterfacePack++;
                            }
                        }
                    }
                    puArgs++;
                    break;

            default:
                MARSHAL_DBGOUT(MSHDBG_ERROR, kprintf(
                    "MshUserToKern: Invalid [in, out] type(%08x).\n",
                    pParams[n]));
                assert(0);
                return E_INVALID_ARGUMENT;
            }
        }
    return ec;
}

ECode CInterfaceStub::MarshalOut(
    /* [in] */ const CIMethodEntry * pMethodInfo,
    /* [in] */ MarshalHeader * pInHeader,
    /* [in] */ UInt32 * puOutInterfaceBuf,
    /* [in, out] */ void * pvOutData,
    /* [in] */ bool_t bOnlyReleaseIn,
    /* [in] */ UInt32 * puKrnArgs)
{
    ECode ec = NOERROR;
    int n, cParams;
    CIBaseType *pParams;
    UInt32 * puArgs;

    // puArgs + 1 , skip this pointer
    // NOTE: here we use the args in user stack ,not the args in current
    // kernel stack because if interrupte or exception occures , it will
    // use the current stack and destroy the data we need
    //
    puArgs = (UInt32 *)*(UInt32*)(pInHeader + 1) + 1;

    assert(GET_INTERFACE_MARK(pMethodInfo->reserved1));
    cParams = pMethodInfo->paramNum;
    pParams = pMethodInfo->params;
    for (n = 0; n < cParams; n++) {
        switch (BT_TYPE(pParams[n])) {
            case BT_TYPE_UINT8:
            case BT_TYPE_UINT16:
            case BT_TYPE_UINT32:
            case BT_TYPE_PUINT8:
            case BT_TYPE_PUINT16:
            case BT_TYPE_PUINT32:
            case BT_TYPE_PUINT64:
            case BT_TYPE_PEGUID:
            case BT_TYPE_PEMUID:
            case BT_TYPE_ASTRING:
            case BT_TYPE_WSTRING:
            case BT_TYPE_STRUCT:
            case BT_TYPE_PSTRUCT:
                puArgs++;
                puKrnArgs++;
                break;

            case BT_TYPE_INTERFACE:
                assert(BT_IS_IN(pParams[n]));
                if (*puArgs) {
                    ((IInterface *)(*puKrnArgs))->Release();
                }
                puArgs++;
                puKrnArgs++;
                break;

            case BT_TYPE_UINT64:
#ifdef _mips
                // Adjust for 64bits align on mips
                if (!(cParams % 2)) {
                    puArgs += 1;
                    puKrnArgs += 1;
                }
#endif
                puArgs += 2;
                puKrnArgs += 2;
                break;

            case BT_TYPE_EGUID:
                puArgs += sizeof(EMuid) / 4 + sizeof(wchar_t *) / 4;
                puKrnArgs += sizeof(EMuid) / 4 + sizeof(wchar_t *) / 4;
                break;

            case BT_TYPE_EMUID:
                puArgs += sizeof(EMuid) / 4;
                puKrnArgs += sizeof(EMuid) / 4;
                break;

            case BT_TYPE_PINTERFACE:
                if (BT_IS_OUT(pParams[n]) && !bOnlyReleaseIn) {
                    if (*puOutInterfaceBuf) {
                        assert(pvOutData);
                        ec = KernMarshalInterface(
                               (IInterface *)(*puOutInterfaceBuf),
                                (InterfacePack *)pvOutData);
                        ((IInterface *)(*puOutInterfaceBuf))->Release();
                        if (FAILED(ec)) {
                            MARSHAL_DBGOUT(MSHDBG_ERROR, kprintf(
                                "MshUserToKern: marshal interface, ec = %x\n",
                                ec));
                            return ec;
                        }
                    }
                    else {
                        ((InterfacePack *)pvOutData)->m_oid = 0;
                    }
                    pvOutData = (InterfacePack *)pvOutData + 1;
                    puOutInterfaceBuf++;
                }
                else if (*puArgs && *(UInt32*)(*puArgs)
                        && BT_IS_IN(pParams[n])) {
                    ((IInterface *)(*(UInt32 *)(*puKrnArgs)))->Release();
                    delete (UInt32 *)(*puKrnArgs);
                }
                puArgs++;
                puKrnArgs++;
                break;

            case BT_TYPE_WSTRINGBUF:
            case BT_TYPE_ASTRINGBUF:
            case BT_TYPE_BUFFEROF:
            case BT_TYPE_ARRAYOF:
                if (*puArgs
                    && CarQuintetFlag_Type_IObject
                        == (((PCARQUINTET)*puArgs)->m_flags
                                & CarQuintetFlag_TypeMask)
                    && BT_IS_IN(pParams[n])) {
                    int used = ((PCARQUINTET)*puKrnArgs)->m_used
                                / sizeof(IInterface *);
                    int *pKrnBuf = (int *)((PCARQUINTET)*puKrnArgs)->m_pBuf;
                    for (int i = 0; i < used; i++) {
                        if (pKrnBuf[i]) {
                            ((IInterface *)pKrnBuf[i])->Release();
                        }
                    }
                    BufferOf<IInterface *>::Free((BufferOf<IInterface *>*)*puKrnArgs);
                }
                puArgs++;
                puKrnArgs++;
                break;

            default:
                MARSHAL_DBGOUT(MSHDBG_ERROR, kprintf(
                    "MshUserToKern: Invalid [in, out] type(%08x).\n",
                    pParams[n]));
                assert(0);
                return E_INVALID_ARGUMENT;
        }
    }

    return ec;
}

PInterface CObjectStub::Probe(
    REIID riid)
{
    int n;

    if (riid == EIID_IInterface) {
        return (IInterface *)this;
    }

    for (n = 0; n < m_cInterfaces; n++) {
        if (riid == m_pInterfaces[n].m_pInfo->iid) {
            break;
        }
    }
    if (n == m_cInterfaces) {
        MARSHAL_DBGOUT(MSHDBG_WARNING, kprintf(
            "KStub(%d): QI failed, iid: ", m_oid));
        MARSHAL_DBGOUT(MSHDBG_WARNING, DUMP_GUID(riid));

        return NULL;
    }

    return m_pInterfaces[n].m_pObject;
}

UInt32 CObjectStub::AddRef(void)
{
    Int32 lRefs = m_cRefs.Increment();

    MARSHAL_DBGOUT(MSHDBG_CREF, kprintf(
        "KStub(%d) AddRef: %d\n", m_oid, lRefs));

    return (UInt32)lRefs;
}

EXTERN KMutex g_objectLock;

UInt32 CObjectStub::Release(void)
{
    ECode ec;

    g_marshalLock.Lock();

    Int32 lRefs = m_cRefs.Decrement();

    if (lRefs == 0) {
        MARSHAL_DBGOUT(MSHDBG_NORMAL, kprintf(
            "KStub destructed, oid(%d)\n", m_oid));

        ec = UnregisterKernExportObject(m_oid);

        if (S_FALSE == ec) {
            g_marshalLock.Unlock();
            return 1; // other thread hold the Stub
        }

        if (m_pInterfaces) {
            if (m_oid != 0) {
                SysUnregister(m_oid);
            }
        }

        g_marshalLock.Unlock();

        delete this;
        return 0;
    }
    else {
        g_marshalLock.Unlock();
    }

    MARSHAL_DBGOUT(MSHDBG_CREF, kprintf(
        "KStub(%d) Release: %d\n", m_oid, lRefs));

    return (UInt32)lRefs;
}

ECode CObjectStub::Aggregate(
    /* [in] */ AggregateType type,
    /* [in] */ PInterface pObj)
{
    return E_NOT_IMPLEMENTED;
}

ECode CObjectStub::GetDomain(
    /* [out] */ PInterface *ppObj)
{
    return E_NOT_IMPLEMENTED;
}

#if defined(_arm) && defined(_EVC)
EXTERN_C void StubInvokeMethod1(
        ECode *pHR, UInt32 *puArgs, UInt32 uMethodAddr, UInt32 regs[8]);

EXTERN_C void StubInvokeMethod2(
        ECode *pHR, UInt32 *puArgs, UInt32 uMethodAddr, UInt32 regs[8]);
#endif

ECode CObjectStub::Invoke(
    /* [in] */ void *pvInData,
    /* [in] */ UInt32 uInSize,
    /* [out] */ void *pvOutData,
    /* [in] */ UInt32 uOutSize)
{
    MarshalHeader *pInHeader;
    UInt32 *puArgs, *puOutInterfaceBuf, uMethodAddr, uMethodIndex;
    ECode ec = E_MARSHAL_DATA_TRANSPORT_ERROR, orghr;
    CInterfaceStub *pCurInterface;
    const CIMethodEntry *pMethodInfo;
    bool_t bOnlyReleaseIn = FALSE;
    bool_t bMshOut = FALSE;
    UInt32 uArgsSize;
#ifdef _x86
    UInt32 uEAX, uEDX, uECX, uESP;
#elif defined(_arm)
#if defined(_GNUC)
    UInt32 r0, r1, r2, r3, ip, lr, sp;
#elif defined(_EVC)
    UInt32 regs[8];
#else
#error Unknown C++ compiler
#endif // defined(_GNUC)
#elif defined(_mips)
    UInt32 uV0, uV1;
    UInt32 uA0, uA1, uA2, uA3;
    UInt32 uT0, uT1, uT2, uT3, uT4, uT5, uT6, uT7, uT8, uT9;
    UInt32 uSp;
#else
#error unknown architecture
#endif

    assert(pvInData != NULL);

    MARSHAL_DBGOUT(MSHDBG_NORMAL,
        kprintf("KStub(%d): in Invoke: isize(%d)\n", m_oid, uInSize));

    pInHeader = (MarshalHeader *)pvInData;

    if (pInHeader->m_uMagic != MARSHAL_MAGIC) {
        MARSHAL_DBGOUT(MSHDBG_ERROR,
            kprintf("KStub: invalid magic - %x\n", pInHeader->m_uMagic));
        goto ErrorExit;
    }

#if defined(_DEBUG)

    if (uInSize < sizeof(MarshalHeader)) {
        goto ErrorExit;
    }
    if (uInSize != pInHeader->m_uInSize) {
        MARSHAL_DBGOUT(MSHDBG_ERROR,
            kprintf("KStub: in size error - %d:%d\n",
                uInSize, pInHeader->m_uInSize + sizeof(MarshalHeader) - 1));
        goto ErrorExit;
    }
    if (pInHeader->m_oid != m_oid) {
        MARSHAL_DBGOUT(MSHDBG_ERROR,
            kprintf("KStub: oid error - %d:%d\n", pInHeader->m_oid, m_oid));
        goto ErrorExit;
    }
    if (pInHeader->m_hInterfaceIndex >= m_cInterfaces) {
        MARSHAL_DBGOUT(MSHDBG_ERROR,
            kprintf("KStub: interface index error - %d:%d\n",
                pInHeader->m_hInterfaceIndex, m_cInterfaces));
        goto ErrorExit;
    }
    MARSHAL_DBGOUT(MSHDBG_NORMAL,
        kprintf("KStub: interface idx(%d), method idx(%d)\n",
            pInHeader->m_hInterfaceIndex, pInHeader->m_hMethodIndex));
#endif

    assert(pInHeader->m_pContext == CTX_USER_2_KERN);
    if (pInHeader->m_hMethodIndex >= 3) {

        pCurInterface = &(m_pInterfaces[pInHeader->m_hInterfaceIndex]);

        uMethodIndex = pInHeader->m_hMethodIndex - 3;

        if (uMethodIndex >= pCurInterface->m_pInfo->methodNumMinus3) {
            MARSHAL_DBGOUT(MSHDBG_ERROR,
                kprintf("KStub: method index out of range - %d:%d\n",
                    uMethodIndex,
                    pCurInterface->m_pInfo->methodNumMinus3));
            goto ErrorExit;
        }

        pMethodInfo = &((pCurInterface->m_pInfo)->methods[uMethodIndex]);

        // + 4 is for add "this"
        uArgsSize = GET_LENGTH(pMethodInfo->reserved1) * 4 + 4;
        puArgs = (UInt32 *)_alloca(
            2 * uArgsSize + MAX_OUT_INTERFACE_ACCOUNT * 4);
        if (!puArgs) {
            MARSHAL_DBGOUT(MSHDBG_ERROR,
                kprintf("KStub error: alloca() failed.\n"));
            ec = E_OUT_OF_MEMORY;
            goto ErrorExit;
        }
#ifdef _x86
        GET_REG(ESP, puArgs);
#endif

        puOutInterfaceBuf = puArgs + 2 * uArgsSize / sizeof(int);
        // copy the context designed by user stackpoint
        memcpy(puArgs, (void *)*(UInt32*)(pInHeader + 1), uArgsSize);

        if (GET_INTERFACE_MARK(pMethodInfo->reserved1)) {
            ec = pCurInterface->UnmarshalIn(pMethodInfo,
                                            pInHeader,
                                            puOutInterfaceBuf,
                                            puArgs + 1);
            if (FAILED(ec)) {
                MARSHAL_DBGOUT(MSHDBG_ERROR,
                    kprintf("KStub error: UnmarshalIn() failed.\n"));
                goto ErrorExit;
            }
            memcpy(puArgs + uArgsSize / sizeof(int), puArgs, uArgsSize);
        }

        *puArgs = (UInt32)pCurInterface->m_pObject; // fill this

        uMethodAddr = pCurInterface->m_pInterface-> \
            m_vPtr->m_vTable[uMethodIndex + 3];

        MARSHAL_DBGOUT(MSHDBG_NORMAL,
            kprintf(
                "KStub: invoke method - argsize(%x), args(%x), addr(%x) \n",
                uArgsSize, puArgs, uMethodAddr));
#ifdef _x86
        GET_REG(EAX, uEAX);
        GET_REG(EDX, uEDX);
        GET_REG(ECX, uECX);
        GET_REG(ESP, uESP);
        assert(uESP == (UInt32)puArgs);
        STUB_INVOKE_METHOD(ec, puArgs, uMethodAddr);
        SET_REG(ECX, uECX);
        SET_REG(EDX, uEDX);
        SET_REG(EAX, uEAX);
#elif defined(_arm)

#if defined(_GNUC)
        if (sizeof(uint32_t) * 4 >= uArgsSize) {
            GET_REG(r0, r0);
            GET_REG(r1, r1);
            GET_REG(r2, r2);
            GET_REG(r3, r3);
            GET_REG(ip, ip);
            GET_REG(lr, lr);
            STUB_INVOKE_METHOD1(ec, puArgs, uMethodAddr);
            SET_REG(lr, lr);
            SET_REG(ip, ip);
            SET_REG(r3, r3);
            SET_REG(r2, r2);
            SET_REG(r1, r1);
            SET_REG(r0, r0);
        }
        else {
            GET_REG(r0, r0);
            GET_REG(r1, r1);
            GET_REG(r2, r2);
            GET_REG(r3, r3);
            GET_REG(ip, ip);
            GET_REG(lr, lr);
            GET_REG(sp, sp);
            STUB_INVOKE_METHOD2(ec, puArgs, uMethodAddr);
            SET_REG(sp, sp);
            SET_REG(lr, lr);
            SET_REG(ip, ip);
            SET_REG(r3, r3);
            SET_REG(r2, r2);
            SET_REG(r1, r1);
            SET_REG(r0, r0);
        }
#elif defined(_EVC)
    if (sizeof(uint32_t) * 4 >= uArgsSize) {
        StubInvokeMethod1(&ec, puArgs, uMethodAddr, regs);
    }
    else {
        StubInvokeMethod2(&ec, puArgs, uMethodAddr, regs);
    }
#else

#error Unknown C++ compiler

#endif // defined(_GNUC)

#elif defined(_mips)
        GET_REG($2, uV0);
        GET_REG($3, uV1);
        GET_REG($4, uA0);
        GET_REG($5, uA1);
        GET_REG($6, uA2);
        GET_REG($7, uA3);
        GET_REG($8, uT0);
        GET_REG($9, uT1);
        GET_REG($10, uT2);
        GET_REG($11, uT3);
        GET_REG($12, uT4);
        GET_REG($13, uT5);
        GET_REG($14, uT6);
        GET_REG($15, uT7);
        GET_REG($24, uT8);
        GET_REG($25, uT9);
        GET_REG($29, uSp);
        STUB_INVOKE_METHOD(ec, puArgs, uMethodAddr);
        SET_REG($29, uSp);
        SET_REG($2, uV0);
        SET_REG($3, uV1);
        SET_REG($4, uA0);
        SET_REG($5, uA1);
        SET_REG($6, uA2);
        SET_REG($7, uA3);
        SET_REG($8, uT0);
        SET_REG($9, uT1);
        SET_REG($10, uT2);
        SET_REG($11, uT3);
        SET_REG($12, uT4);
        SET_REG($13, uT5);
        SET_REG($14, uT6);
        SET_REG($15, uT7);
        SET_REG($24, uT8);
        SET_REG($25, uT9);
#else
#error unknown architecture
#endif
        puArgs += uArgsSize / sizeof(int);

        if (GET_INTERFACE_MARK(pMethodInfo->reserved1)) {
            if (SUCCEEDED(ec)) {
                bMshOut = TRUE;
            }
            else if (GET_IN_INTERFACE_MARK(pMethodInfo->reserved1)){
                bOnlyReleaseIn = TRUE;
            }

            if (bMshOut || bOnlyReleaseIn) {
                orghr = pCurInterface->MarshalOut(pMethodInfo, pInHeader, \
                               puOutInterfaceBuf, pvOutData, bOnlyReleaseIn, \
                               puArgs + 1);
                if (FAILED(orghr)) {
                    MARSHAL_DBGOUT(MSHDBG_ERROR, kprintf(
                        "KStub: marshal out args fail, ec(%x)\n", orghr));
                    ec = orghr;
                    goto ErrorExit;
                }
            }
        }

    }
    else if (pInHeader->m_hMethodIndex == 0) {
        MARSHAL_DBGOUT(MSHDBG_ERROR,
            kprintf("KStub error: Remote Probe().\n"));
        ec = E_INVALID_OPERATION; // Do not allow remote Probe().
        goto ErrorExit;
    }
    else if (pInHeader->m_hMethodIndex == 1) {
        // use "ec" to transport the reference
        ec = this->AddRef();

        MARSHAL_DBGOUT(MSHDBG_NORMAL, kprintf(
            "KStub: remote AddRef(), cRefs(%d)\n", ec));
        goto Exit;
    }
    else {
        // use "ec" to transport the reference
        ec = this->Release();

        MARSHAL_DBGOUT(MSHDBG_NORMAL, kprintf(
            "KStub: remote Release(), cRefs(%d)\n", ec));
        goto Exit;
    }

Exit:
    MARSHAL_DBGOUT(MSHDBG_NORMAL, kprintf(
        "KStub(%d): invoke server method ok, _SysReply osize(%d)\n",
       pInHeader->m_oid, pInHeader->m_uOutSize));
ErrorExit:
    return ec;
}

ECode CObjectStub::GetOid(
    /* [out] */ oid_t *pOid)
{
    *pOid = m_oid;
    return NOERROR;
}

ECode CObjectStub::GetClsid(
    /* [out] */ EMuid *pClsid)
{
    *pClsid = ((CIClassEntry*)m_pInfo)->clsid;
    return NOERROR;
}

ECode CObjectStub::GetClassEntry(
    /* [out] */ UInt32 *pClassEntry)
{
    *pClassEntry = m_pInfo;
    return NOERROR;
}

ECode CObjectStub::InterfaceIndex(
    /* [in] */ IInterface *pObj,
    /* [out] */ UInt32 *puIndex)
{
    for (UInt32 n = 0; n < (UInt32)m_cInterfaces; n++) {
        if (m_pInterfaces[n].m_pObject == pObj) {
            *puIndex = n;
            return NOERROR;
        }
    }
    MARSHAL_DBGOUT(MSHDBG_WARNING, kprintf(
        "KStub(%d): InterfaceIndex failed - pObj(%x)\n", m_oid, pObj));

    return E_NO_INTERFACE;
}

ECode CObjectStub::S_CreateObject(
    /* [in] */ IInterface *pObject,
    /* [out] */ IStub **ppIStub)
{
    return S_CreateObject(NULL, pObject, ppIStub);
}

ECode CObjectStub::S_CreateObject(
    /* [in] */ const wchar_t *pwszName,
    /* [in] */ IInterface *pObject,
    /* [out] */ IStub **ppIStub)
{
    CObjectStub *pStub;
    CInterfaceStub *pInterfaces;
    IInterface *pObj;
    EMuid *pClsid;
    const CIClassEntry *pClassInfo;
    UInt32 uIndex;
    ECode ec = NOERROR;
    int n;

    assert(pObject != NULL);
    pStub = new CObjectStub;
    if (!pStub) {
        return E_OUT_OF_MEMORY;
    }
    pStub->AddRef();

    pClsid = (EMuid*)pObject->Probe(EIID_CLASS_INFO);
    if (!pClsid) {
        MARSHAL_DBGOUT(MSHDBG_ERROR, kprintf(
            "Create kstub: interface do not support EIID_CLASS_INFO QI.\n"));
        goto ErrorExit;
    }

    MARSHAL_DBGOUT(MSHDBG_NORMAL, kprintf(
        "QI class info ok. EMuid is:\n"));
    MARSHAL_DBGOUT(MSHDBG_NORMAL, DUMP_CLSID((RClassID)*pClsid));
    ec = LookupServerClassEntry(*pClsid, &pClassInfo);
    if (FAILED(ec)) {
        ec = LookupSharedClassEntry(*pClsid, (CIClassEntry**)&pClassInfo);
        if (FAILED(ec)) {
            MARSHAL_DBGOUT(MSHDBG_ERROR,
                kprintf("Create kstub: class info not found.\n"));
            ec = E_NO_CLASS_INFO;
            goto ErrorExit;
        }
    }

    pStub->m_pInfo = (UInt32)pClassInfo;

    pInterfaces = new CInterfaceStub[pClassInfo->interfaceNum];
    if (!pInterfaces) {
        MARSHAL_DBGOUT(MSHDBG_ERROR, kprintf(
            "Create kstub: out of memory.\n"));
        ec = E_OUT_OF_MEMORY;
        goto ErrorExit;
    }
    pStub->m_cInterfaces = pClassInfo->interfaceNum;

    pStub->m_pInterfaces = pInterfaces;
    pObject->AddRef();
    for (n = 0; n < pClassInfo->interfaceNum; n++) {
        CIInterfaceEntry *pInterfaceInfo =
            (CIInterfaceEntry *)GetUnalignedPtr(pClassInfo->interfaces + n);
        pObj =  pObject->Probe(pInterfaceInfo->iid);
        if (!pObj) {
            MARSHAL_DBGOUT(MSHDBG_ERROR,
                kprintf("Create kstub: no such interface.\n"));
            ec = E_NO_INTERFACE;
            pObject->Release();
            goto ErrorExit;
        }
        pInterfaces[n].m_pInfo = pInterfaceInfo;
        pInterfaces[n].m_pObject = pObj;
    }

    ec = pStub->InterfaceIndex(pObject, &uIndex);
    assert(SUCCEEDED(ec));

    if (!pwszName) {
        ec = _SysRegister((IStub *)pStub, uIndex, &pStub->m_oid, NULL, NULL);
    }
    else {
        ec = _SysRegisterCommon(pwszName, (IStub *)pStub, uIndex, \
                                &pStub->m_oid, NULL, NULL);
    }

    if (FAILED(ec)) {
        pObject->Release();
        MARSHAL_DBGOUT(MSHDBG_ERROR, kprintf(
            "KStub: register server fail.\n"));
        goto ErrorExit;
    }
    MARSHAL_DBGOUT(MSHDBG_NORMAL,
        kprintf("Create kstub: _SysRegister ok. oid = %d\n", pStub->m_oid));

    ec = RegisterKernExportObject(pStub->m_oid, pObject, pStub);
    if (FAILED(ec)) {
        pObject->Release();
        MARSHAL_DBGOUT(MSHDBG_ERROR, kprintf(
            "Create kstub: register export object failed, ec(%x)\n", ec));
        goto ErrorExit;
    }

    if (ppIStub) *ppIStub = (IStub *)pStub;

    return NOERROR;

ErrorExit:

    delete pStub;
    return ec;
}

CObjectStub::~CObjectStub()
{
    if (m_pInterfaces) {
        if (m_oid != 0) {
            m_pInterfaces[0].m_pObject->Release();
//            SysUnregister(m_oid);
        }

        delete [] m_pInterfaces;
    }
}
